Skip to content

bpo-44687: Fix unintended closing file error when peeking a BufferedReader object#28457

Merged
zooba merged 8 commits into
python:mainfrom
AngstyDuck:iobuffreader_stop_closing_file_error_during_peek
Oct 1, 2021
Merged

bpo-44687: Fix unintended closing file error when peeking a BufferedReader object#28457
zooba merged 8 commits into
python:mainfrom
AngstyDuck:iobuffreader_stop_closing_file_error_during_peek

Conversation

@AngstyDuck

@AngstyDuck AngstyDuck commented Sep 19, 2021

Copy link
Copy Markdown
Contributor

When the user runs the peek() function twice on a BufferedReader object, a closed file error may unintentionally be raised on the second time. This PR applies a check specific to the peek() function which runs only when the previous file operation is a peek().

https://bugs.python.org/issue44687

@liquidpele

Copy link
Copy Markdown

What about a read() after the first peek too? I’d expect peek() to allow a read afterward.

@AngstyDuck

Copy link
Copy Markdown
Contributor Author

Thanks for pointing it out, I'll alter the fix to accommodate the order you've mentioned as well.

@@ -0,0 +1 @@
Add a new :c:macro:`PEEK_CHECK_CLOSED` macro to check if a file is closed using a method specific to BufferedReader.peek() No newline at end of file

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The NEWS entry should be relevant to users, not developers. This would be a better commit message, while the PR title would be better for NEWS.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

thanks for the feedback, i've updated the NEWS entry to incorporate more of the PR title. Hope that works 👍

Comment thread Modules/_io/bufferedio.c Outdated
CHECK_CLOSED(self, "peek of closed file")

// use a check specific to peek if the previous file operation was not a read
if (Py_SAFE_DOWNCAST(self->pos, Py_off_t, Py_ssize_t) == 0) {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm reading this correctly, this just means we haven't done a read or a seek yet?

Wouldn't it be better to not close the file after a peek, but wait for the read? If the read never comes, it'll be closed when the stream is closed as it normally would.

@AngstyDuck AngstyDuck Sep 24, 2021

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I'm reading this correctly, this just means we haven't done a read or a seek yet?

thanks for your comment, and yes the if condition checks if a read or a seek has been done before.

Wouldn't it be better to not close the file after a peek, but wait for the read? If the read never comes, it'll be closed when the stream is closed as it normally would.

I considered this solution initially as well, but unfortunately based on the example provided, the closing of the file is actually done by one of the methods of the object that requests.get("https://amazon.com", stream=True).raw returns.

I've just pushed an alternate fix, where I've reset some attributes of BufferedReader when its method closed() has been called. I believe this fixes the bug while passing the test case I've previously encountered which prompted me to write this i condition in the first place. Do let me know what you think.

…new check now works regardless of which method was called before peek()
…thub.com:AngstyDuck/cpython into iobuffreader_stop_closing_file_error_during_peek
@AngstyDuck

Copy link
Copy Markdown
Contributor Author

After digging into the issue further, I've realised that the bug can be seen for all methods that use the original check CHECK_CLOSED. The latest commit not only replaces the old check entirely with the new one, but also fixes the issue in a way where any methods (read/seek/peek) can be called before the peek() in question. Do let me know what you think 👍

Comment thread Misc/NEWS.d/next/C API/2021-09-19-17-18-25.bpo-44687.3fqDRC.rst Outdated
…7.3fqDRC.rst

Co-authored-by: Steve Dower <steve.dower@microsoft.com>
@AngstyDuck AngstyDuck requested a review from zooba September 30, 2021 10:42
@zooba zooba merged commit a450398 into python:main Oct 1, 2021
@miss-islington

Copy link
Copy Markdown
Contributor

Thanks @AngstyDuck for the PR, and @zooba for merging it 🌮🎉.. I'm working now to backport this PR to: 3.9, 3.10.
🐍🍒⛏🤖

@bedevere-bot

Copy link
Copy Markdown

GH-28685 is a backport of this pull request to the 3.10 branch.

@bedevere-bot

Copy link
Copy Markdown

GH-28686 is a backport of this pull request to the 3.9 branch.

miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Oct 1, 2021
… even when the underlying file is closed (pythonGH-28457)

(cherry picked from commit a450398)

Co-authored-by: AngstyDuck <solsticedante@gmail.com>
miss-islington pushed a commit to miss-islington/cpython that referenced this pull request Oct 1, 2021
… even when the underlying file is closed (pythonGH-28457)

(cherry picked from commit a450398)

Co-authored-by: AngstyDuck <solsticedante@gmail.com>
miss-islington added a commit that referenced this pull request Oct 1, 2021
… even when the underlying file is closed (GH-28457)

(cherry picked from commit a450398)

Co-authored-by: AngstyDuck <solsticedante@gmail.com>
zooba pushed a commit that referenced this pull request Oct 1, 2021
… even when the underlying file is closed (GH-28457)

Co-authored-by: AngstyDuck <solsticedante@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants